#include "command.h"

// 初始化一个用来保存路径的栈
int pathStackInit(pathStack_t* pathStack){
    bzero(pathStack,sizeof(pathStack_t));
    pathStack->top=-1;
    pathStack->rootPathPointer=-1;// 只在curPathInit中初始化一次
    return 0;
}
// 出栈成功返回0，失败返回-1
int popStack(pathStack_t* pathStack){
    if(pathStack->top != -1){
        free(pathStack->pathArr[pathStack->top]);
        --pathStack->top;
    }else{
        return -1;
    }
    return 0;
}
// 压栈成功返回0，失败返回-1
int pushStack(pathStack_t* pathStack,const char * str){
    if((pathStack->top)<(PATHSTACK_MAXSIZE-1)){
        char* pathName = (char*)calloc(strlen(str)+1,sizeof(char));
        strcpy(pathName,str);
        //printf("push: %s\n",pathName);
        ++(pathStack->top);
        pathStack->pathArr[pathStack->top]=pathName;
    }else{
        return -1;
    }
    return 0;
}
//销毁栈，正常销毁返回0，销毁失败返回-1
int destroyStack(pathStack_t *pathStack){
    if(pathStack == NULL){
        return -1;
    }
    while(pathStack->top >= 0){
        popStack(pathStack);
    }
    pathStack->top = -1;
    return 0;
}
// 将字符串保存的路径 存在路径栈中,加入对../.的处理，加入对客户端眼里的绝对路径的处理，保证返回的是一个完整的绝对路径
// 正确处理返回0，发生错误返回-1
int saveStrPathToStack (char*path,pathStack_t* pathStack){
    /* printf("save -----------------------1\n"); */
    char delim[] = "/";
    char* saveptr=NULL;
    /* printf("save -----------1/2---------|%s|\n",path); */
    char* token = strtok_r(path,delim,&saveptr);
    /* pintf("save -----------------------3\n"); */
    if(path[0]=='/'){
        while(pathStack->top>pathStack->rootPathPointer){
            popStack(pathStack);
        }
        //=======DEBUG==========
        char tempPrintPath[1024];
        getPath(pathStack,tempPrintPath);
        //printf("DEBUG1: tempPrintPath:|%s|\n",tempPrintPath);
        //======================
    }
    // 处理..和.的情况，并将token压栈
    while(token!=NULL){
        /* printf("DEBUG1:token:|%s|\n",token); */
        if(strcmp(token,"..")==0){
            if(pathStack->top==pathStack->rootPathPointer){
                printf("saveStrPathToStack: path error (to much ..)\n");
                return -1;// ../../../...太多，超出了允许访问的位置
            }
            popStack(pathStack);
        } else if(strcmp(token,".")!=0){
            pushStack(pathStack, token);
        }
        token = strtok_r(NULL,delim,&saveptr);
    }
    return 0;
}
// 获取路径
int getPath(const pathStack_t* pathStack,char* result){       
    result[0]='\0';
    for(int i = 0;i<=pathStack->top;++i){
        strncat(result,"/",2);
        strncat(result,pathStack->pathArr[i],PATHNAME_MAXLEN);
    }   
    return 0;     
} 

// 打印路径栈
int printPathStack(pathStack_t* pathStack){
    //printf("pathStack: ");
    if(pathStack->top==-1){
        printf("null\n");
    }
    for(int i = 0;i<=pathStack->top;++i){
        /* printf("%d:%s ",i,pathStack->pathArr[i]); */
        //printf("%s ",pathStack->pathArr[i]);
    }
    //printf("\n");
    return 0;
}
// 初始化表示客户端访问路径的路径栈，目前使用调用方传入的绝对路径
int curPathInit(pathStack_t* pCurPathStack, char* rootPath){
    bzero(pCurPathStack,sizeof(pathStack_t));
    pCurPathStack->top=-1;
    saveStrPathToStack(rootPath,pCurPathStack);
    pCurPathStack->rootPathPointer=pCurPathStack->top;
    return 0;
}
// 实现客户端cd操作，传入cd后跟的目的目录名，返回的路径名在传入的栈内
int my_cd(char *path, pathStack_t *pCurpathStack){
    pathStack_t tempStack;
    pathStackInit(&tempStack);

    // 复制当前路径
    for (int i = 0; i <= pCurpathStack->top; i++) {
        if (pushStack(&tempStack, pCurpathStack->pathArr[i])) {
            destroyStack(&tempStack);
            return -1;
        }
    }
    tempStack.rootPathPointer = pCurpathStack->rootPathPointer;    

    char new_path[BUFSIZE] = {0};
    int ret = saveStrPathToStack(path, &tempStack);  // 拼接获得客户端想要进入的绝对路径 
    if(ret != 0){
        printf("my_cd: error path!\n");
        return -1;
    }
    getPath(&tempStack, new_path); // 获取绝对路径
    if (access(new_path, F_OK) != 0) {  // 判断是否存在这条绝对路径，若没有这条绝对路径，则返回-1
        getPath(pCurpathStack, new_path); 
        return -1;
    }
    while(pCurpathStack->top >= 0){
        popStack(pCurpathStack);
    }
    for(int i = 0; i <= tempStack.top; i++){
        pushStack(pCurpathStack, tempStack.pathArr[i]);
    }
    pCurpathStack->rootPathPointer = tempStack.rootPathPointer;
    return 0;
}
// 实现打印所有目的目录下的所有子目录和文件，返回的result数组中包含需要打印的内容
int my_ls(char *path, pathStack_t *pCurpathStack, char *result){
    pathStack_t tempStack;
    pathStackInit(&tempStack);

    // 复制当前路径
    for (int i = 0; i <= pCurpathStack->top; i++) {
        if (pushStack(&tempStack, pCurpathStack->pathArr[i])) {
            destroyStack(&tempStack);
            return -1;
        }
    }
    tempStack.rootPathPointer = pCurpathStack->rootPathPointer;    

    char new_path[PATHNAME_MAXLEN] = {0};

    saveStrPathToStack(path, &tempStack);
    getPath(&tempStack, new_path);
    if (access(new_path, F_OK) != 0) {  // 判断是否存在这条绝对路径，若没有这条绝对路径，
        perror("my_ls");
        result[0]='\0';
        strncat(result,"no such dir.\n",128);
        return -1;
    }

    DIR *dirp = opendir(new_path);  // 打开拼接得到的绝对路径的目录流
    /* ERROR_CHECK(dirp, NULL, "opendir failed"); */

    struct dirent *dirent_p;
    char buf[BUFSIZE] = {0};

    while((dirent_p = readdir(dirp)) != NULL){
        /* bzero(buf, sizeof(buf)); */
        /* sprintf(buf, "%s\t", dirent_p->d_name); */
        /* strcpy(buf, "\033[34m"); */
        /* strcat(result, buf);  // 把获取到的子目录名和文件名写入到result数组 */
        /* strcat(result, "\033[0m"); */
        bzero(buf, sizeof(buf));
        /* bzero(result, sizeof(result)); // 假设result也需要清空 */

        // 先添加颜色代码，再添加目录名，最后添加重置代码
        strcat(result, "\033[34m");    // 添加蓝色开始标记
        sprintf(buf, "%.5s  ", dirent_p->d_name);
        strcat(result, buf);           // 添加目录名
        strcat(result, "\033[0m");     // 添加颜色重置标记
    }

    closedir(dirp);
    destroyStack(&tempStack);
    return 0;
}
// 删除指定文件名操作
int my_rmFile(char *fileName, pathStack_t *pCurpathStack){
    pathStack_t tempStack;
    pathStackInit(&tempStack);

    // 复制当前路径
    for (int i = 0; i <= pCurpathStack->top; i++) {
        if (pushStack(&tempStack, pCurpathStack->pathArr[i])) {
            destroyStack(&tempStack);
            return -1;
        }
    }
    tempStack.rootPathPointer = pCurpathStack->rootPathPointer;    

    char new_path[BUFSIZE]={0};
    saveStrPathToStack(fileName,&tempStack);
    getPath(&tempStack,new_path);
    if(remove(new_path) != 0){  // 删除指定文件名对应的绝对路径
        perror("my_rmFile");
        return -1;
    }
    destroyStack(&tempStack);
    /* printf("my_rmFile after\n"); */
    return 0;
}

// 将客户端当前访问的路径写在result中
int my_pwd(pathStack_t* pCurPathStack,char * result){
    result[0]='\0';
    strncat(result,"/",2);
    for(int i = pCurPathStack->rootPathPointer+1;i<=pCurPathStack->top;++i){
        strncat(result,pCurPathStack->pathArr[i],FILENAME_MAX);
        strncat(result,"/",2);
    }
    return 0;
}
// 创建指定的目录操作
int my_mkdir(char *dirName, pathStack_t *pCurpathStack){
    pathStack_t tempStack;
    pathStackInit(&tempStack);

    // 复制当前路径
    for (int i = 0; i <= pCurpathStack->top; i++) {
        if (pushStack(&tempStack, pCurpathStack->pathArr[i])) {
            destroyStack(&tempStack);
            return -1;
        }
    }
    tempStack.rootPathPointer = pCurpathStack->rootPathPointer;    

    char new_path[BUFSIZE] = {0};
    saveStrPathToStack(dirName, &tempStack);
    getPath(&tempStack, new_path);
    /* printf("command.c/mkdir:new path:%s\n",new_path); */

    if (mkdir(new_path, 0777) == -1) {
        // 创建失败处理
        perror("my_mkdir");
        return -1;
    }
    destroyStack(&tempStack);
    return 0;
}
// 删除指定的目录操作
int my_rmdir(char *dirName, pathStack_t *pCurpathStack){
    pathStack_t tempStack;
    pathStackInit(&tempStack);

    // 复制当前路径
    for (int i = 0; i <= pCurpathStack->top; i++) {
        if (pushStack(&tempStack, pCurpathStack->pathArr[i])) {
            destroyStack(&tempStack);
            return -1;
        }
    }
    tempStack.rootPathPointer = pCurpathStack->rootPathPointer;    

    char new_path[BUFSIZE] = {0};
    saveStrPathToStack(dirName, &tempStack);
    getPath(&tempStack, new_path);

    if (rmdir(new_path) == -1) {
        // 删除失败处理
        perror("my_rmdir");
        return -1;
    } 
    destroyStack(&tempStack);
    return 0;
}

int my_gets(char* srcPath,char* destPath,pathStack_t* pCurPathStack,char* returnFileName){
    pathStack_t tempStack;
    pathStackInit(&tempStack);
    // 复制当前路径
    for (int i = 0; i <= pCurPathStack->top; i++) {
        if (pushStack(&tempStack, pCurPathStack->pathArr[i])) {
            destroyStack(&tempStack);
            return -1;
        }
    }
    tempStack.rootPathPointer = pCurPathStack->rootPathPointer;

    char new_path[BUFSIZE]={0};
    int ret = saveStrPathToStack(srcPath,&tempStack);
    if(ret == -1){
        return -1;
    }
    getPath(&tempStack,new_path);
    if (access(new_path, F_OK) != 0) {  // 判断是否存
        printf("command.c/my_gets: path no found\n");
        destPath[0]='\0';
        return -1;
    }
    destPath[0]='\0';
    strcpy(destPath,new_path);
    returnFileName[0]='\0';
    strcpy(returnFileName,tempStack.pathArr[tempStack.top]);
    destroyStack(&tempStack);
    return 0;
}

int my_puts(char* srcPath,char* destPath,pathStack_t* pCurPathStack){
    pathStack_t tempStack;
    pathStackInit(&tempStack);
    // 复制当前路径
    for (int i = 0; i <= pCurPathStack->top; i++) {
        if (pushStack(&tempStack, pCurPathStack->pathArr[i])) {
            destroyStack(&tempStack);
            return -1;
        }
    }
    tempStack.rootPathPointer = pCurPathStack->rootPathPointer;

    char new_path[BUFSIZE]={0};
    int ret = saveStrPathToStack(srcPath,&tempStack);
    if(ret == -1){
        return -1;
    }
    getPath(&tempStack,new_path);
    char fileFatherPath[BUFSIZE]={0};
    popStack(&tempStack);
    getPath(&tempStack,fileFatherPath);
    if (access(fileFatherPath, F_OK) != 0) {  // 判断是否存
        printf("command.c/my_gets: dir no found\n");
        return -1;
    }
    destPath[0]='\0';
    strcpy(destPath,new_path);
    destroyStack(&tempStack);
    return 0;
}
